热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

简洁性|切线_AndroidOkHttp+Retrofit+Rxjava+Hilt实现网络请求框架

篇首语:本文由编程笔记#小编为大家整理,主要介绍了AndroidOkHttp+Retrofit+Rxjava+Hilt实现网络请求框架相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Android OkHttp+Retrofit+Rxjava+Hilt实现网络请求框架相关的知识,希望对你有一定的参考价值。



🔥 介绍

本文通过OkHttp+Retrofit+Rxjava+Hilt实现一个网络请求框。


💥 最终代码

        iWanandroidService.register(map)
                .compose(ResponseTransformer.obtain())
                .subscribe(registerData -> 
                    //请求成功
                , new ErrorConsumer() 
                    @Override
                    protected void error(ApiException e) 
                        //请求失败
                    
                );

是不是特别省事。


💥 项目结构


🔥 OkHttp

💥 OkHttp是什么

OkHttp 是一个默认高效的 HTTP 客户端:


  • HTTP/2 支持允许对同一主机的所有请求共享一个 socket。

  • 连接池减少了请求延迟(如果 HTTP/2 不可用)。

  • 透明 GZIP 可缩小下载大小。

  • 响应缓存完全避免网络重复请求。

  • 网路出现问题后,OkHttp会保持不变,自动从问题中恢复。

官方文档

简单使用+源码解读

OkHttp的时候就不单独介绍了。

缺陷:


  • 网络请求的接口配置繁琐,尤其是需要配置复杂请求body,请求头,参数的时候;

  • 数据解析过程需要用户手动拿到responsbody进行解析,不能复用;

  • 无法适配自动进行线程的切换。

  • 万一我们的存在嵌套网络请求就会陷入“回调陷阱”。


🔥 Retrofit

💥 Retrofit是什么

Retrofit 基于 OkHttp,网络请求工作实际由OkHttp完成,而Retrofit主要负责接口的封装

Retrofit不仅具备了OkHttp的高效特性,还有以下优势:


  • 支持RESTful API设计风格。

  • 通过注解配置请求:包括请求方法、请求参数、请求头,返回值等。

  • 可以搭配多种Converter将获得的数据自动解析和序列化:支持Gson,Jackson,Protobuff等。提供了对RxJava的支持。

  • 请求速度快,使用非常方便灵活。



注意:Retrofit不具备网络请求功能,因此你要设置分发器拦截器等则需要在OkHttpClient中设置。



💥 Retrofit注解

官方文档也提供了各类注解的用法。


🔥 OkHttp+Retrofit 实例

💥 添加依赖

dependencies 
    implementation 'com.squareup.retrofit2:retrofit:2.8.1' // 必要依赖,retrofit
    implementation 'com.squareup.retrofit2:converter-gson:2.8.1' // 必要依赖,解析json字符
    implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0' //非必要依赖,打印日志

💥 定义请求接口

public interface IWanAndroidService 
    String BASE_URL = "https://www.wanandroid.com/";
    @GET("banner/json")
    Call>> homeBanner();
    @POST("user/register")
    @FormUrlEncoded
    Call> register(@FieldMap Map map);

💥 设置OkHttp+Retrofit

public class NetworkManager 
    private static volatile NetworkManager instances;
    private static volatile OkHttpClient okHttpClient;
    private static volatile Retrofit retrofit;
    public static NetworkManager getInstance() 
        if (instances == null) 
            synchronized (NetworkManager.class) 
                if (instances == null) 
                    instances = new NetworkManager();
                
            
        
        return instances;
    
    private static int TIME_OUT = 30; //30秒超时断开连接
    private OkHttpClient initClient() 
        if (okHttpClient == null) 
            synchronized (NetworkManager.class) 
                if (okHttpClient == null) 
                    //请求日志打印
                    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(message -> 
                        try 
                            MLog.e(URLDecoder.decode(message, "utf-8"));
                         catch (UnsupportedEncodingException e) 
                            e.printStackTrace();
                            MLog.e(message);
                        
                    );
                    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
                    //注释1:创建OkHttpClient
                    okHttpClient = new OkHttpClient.Builder()
                            .sslSocketFactory(new NetworkSSL(TrustManager.trustAllCert), TrustManager.trustAllCert)
                            .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
                            .addInterceptor(loggingInterceptor)
                            .readTimeout(TIME_OUT, TimeUnit.SECONDS)
                            .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
                            .build();
                
            
        
        return okHttpClient;
    
    public Retrofit initRetrofit() 
        if (retrofit == null) 
            synchronized (NetworkManager.class) 
                if (retrofit == null) 
                    //注释2:创建Retrofit
                    retrofit = new Retrofit.Builder()
                            .client(initClient())//选填
                            .baseUrl(IWanAndroidService.BASE_URL)//必填
                            .addConverterFactory(GsonConverterFactory.create())//选填(数据转换器,解析)
                            .build();
                
            
        
        return retrofit;
    

  • 注释1:创建OkHttpClient对象,构建一个网络类型的实例,一般会将所有的网络请求使用同一个单例对象。(如果OkHttpClient使用默认,可不设置)

  • 注释2:创建Retrofit对象,构建一个网络请求的载体对象,在build的时候有非常多的初始化内容,如设置OkHttpClient、设置请求的url,添加数据转换器等。


💥 网络请求

            //GET
            //注释1:动态获取IWanAndroidService对象
            IWanAndroidService service = NetworkManager.getInstance().initRetrofit().create(IWanAndroidService.class);
            //注释2:网络请求
            service.homeBanner().enqueue(new Callback>>() 
                @Override
                public void onResponse(Call>> call, Response>> response) 
                    if (response.body().getData() != null) 
                        MLog.e(response.body().getData().get(0).toString());
                        binding.loginTvContent.setText(response.body().getData().get(0).toString());
                    
                
                @Override
                public void onFailure(Call>> call, Throwable t) 
                    MLog.e(t.getMessage());
                
            );
            
            //POST
            Map map &#61; new HashMap<>();
            map.put("username", account);
            map.put("password", passsword);
            map.put("repassword", passsword);
            NetworkManager.getInstance().initRetrofit().create(IWanAndroidService.class)
                    .register(map).enqueue(new Callback>() 
                &#64;Override
                public void onResponse(Call> call, Response> response) 
                    if (response.body().getData() !&#61; null) 
                        MLog.e(response.body().getData().toString());
                        binding.loginTvContent.setText(response.body().getData().toString());
                    
                
                &#64;Override
                public void onFailure(Call> call, Throwable t) 
                    MLog.e(t.getMessage());
                
            );

Retrofit的精髓&#xff1a;为统一配置网络请求完成动态代理的设置。


&#x1f4a5; 效果图


&#x1f525; Rxjava

RxJava使用了观察者模式建造者模式中的链式调用。

观察者模式&#xff1a;

Observable&#xff08;被观察者&#xff09;被Observer&#xff08;观察者&#xff09;订阅&#xff08;Subscribe&#xff09;之后&#xff0c;Observable在发出消息的时候会通知对应的Observer&#xff0c;并且&#xff0c;一个Observable可以有被多个Observer订阅。

链式调用&#xff1a;调用对应的方法对原对象进行处理后返回原对象&#xff0c;从而做到链式调用。

参与者&#xff1a;


  • Observable&#xff1a;被观察者&#xff0c;也就是消息的发送者

  • Observer&#xff1a;观察者&#xff0c;消息的接收者

  • Subscriber&#xff1a;订阅者&#xff0c;观察者的另一种表示

  • Scheduler&#xff1a;调度器&#xff0c;进行线程切换

RxJava当然是优秀而且强大的&#xff0c;有以下优势:


  • 具备响应式编程该有的特性。

  • 为异步而生&#xff0c;无需手动创建线程&#xff0c;并具备线程切换能力。

  • 支持链式调用&#xff0c;保证代码的简洁性。

  • 各种操作符&#xff0c;功能非常强大&#xff0c;满足各种业务需求。

  • 简化了异常的处理。

RxJava适用场景:网络请求、数据库读写、文件读写、定时任务等各种耗时操作需要通过异步来完成的操作都可以使用RxJava。


&#x1f4a5; 添加依赖(新增)

    implementation "io.reactivex.rxjava2:rxjava:2.2.6" // 必要rxjava依赖
    implementation "io.reactivex.rxjava2:rxandroid:2.1.0" // 必要rxandrroid依赖&#xff0c;切线程时需要用到
    ...
    implementation &#39;com.squareup.retrofit2:adapter-rxjava2:2.5.0&#39; // 必要依赖&#xff0c;和rxjava结合必须用到

&#x1f4a5; 修改请求接口

public interface IWanAndroidService 
    String BASE_URL &#61; "https://www.wanandroid.com/";
    //OkHttp&#43;Retrofit
    //OkHttp&#43;Retrofit&#43;RxJava
    &#64;GET("banner/json")
    Observable>> homeBanner();
    &#64;POST("user/register")
    &#64;FormUrlEncoded
    Observable> register(&#64;FieldMap Map map);

&#x1f4a5; 设置OkHttp&#43;Retrofit&#43;RxJava

    public Retrofit initRetrofitRxJava() 
        if (retrofit &#61;&#61; null) 
            synchronized (NetworkManager.class) 
                if (retrofit &#61;&#61; null) 
                    retrofit &#61; new Retrofit.Builder()
                            .client(initClient())//选填
                            .baseUrl(IWanAndroidService.BASE_URL)//必填
                            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//新增网络请求适配器
                            .addConverterFactory(GsonConverterFactory.create())//选填(数据转换器&#xff0c;解析)
                            .build();
                
            
        
        return retrofit;
    

&#x1f4a5; 进行网络请求

        NetworkManager.getInstance().initRetrofitRxJava()
                .create(IWanAndroidService.class)
                .homeBanner()
                .subscribeOn(Schedulers.io())//切换到IO线程
                .observeOn(AndroidSchedulers.mainThread())//切换到主线程
                // 添加订阅
                .subscribe(listResponseData -> 
                    //请求成功
                    if (listResponseData !&#61; null) 
                        MLog.e(listResponseData.getData().get(0).toString());
                        binding.loginTvContent.setText(listResponseData.getData().get(0).toString());
                    
                , throwable -> 
                    //请求失败
                    MLog.e(throwable.getMessage());
                );

&#x1f4a5; 效果图


&#x1f4a5; 进一步封装

由于请求过于繁琐&#xff0c;咱们试着复进一步封装。


&#x1f300; 统一异常处理(自定义ApiException)

public class ApiException extends Exception 
    //未知错误
    public static final int UNKNOWN &#61; 1000;
    //解析错误
    public static final int PARSE_ERROR &#61; 1001;
    //网络错误/连接错误
    public static final int NETWORK_ERROR &#61; 1002;
    private int code;
    private String displayMessage;
    public ApiException(int code, String displayMessage) 
        this.code &#61; code;
        this.displayMessage &#61; displayMessage;
    
    public int getCode() 
        return code;
    
    public void setCode(int code) 
        this.code &#61; code;
    
    public String getDisplayMessage() 
        return displayMessage;
    
    public void setDisplayMessage(String displayMessage) 
        this.displayMessage &#61; displayMessage;
    
    public static ApiException handleException(Throwable e) 
        ApiException ex;
        if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) 
            //解析错误
            ex &#61; new ApiException(PARSE_ERROR, e.getMessage());
            return ex;
         else if (e instanceof ConnectException) 
            //网络错误
            ex &#61; new ApiException(NETWORK_ERROR, e.getMessage());
            return ex;
         else if (e instanceof UnknownHostException || e instanceof SocketTimeoutException) 
            //连接错误
            ex &#61; new ApiException(NETWORK_ERROR, e.getMessage());
            return ex;
         else 
            //未知错误
            ex &#61; new ApiException(UNKNOWN, e.getMessage());
            return ex;
        
    

&#x1f300; 统一异常处理(实现Consumer接口)

public abstract class ErrorConsumer implements Consumer 
    &#64;Override
    public void accept(&#64;NotNull Throwable throwable) throws Exception 
        //对异常进行处理
        ApiException exception;
        if (throwable instanceof ApiException) 
            exception &#61; (ApiException) throwable;
         else 
            exception &#61; ApiException.handleException(throwable);
        
        //调用error方法
        error(exception);
    
    //使用时实现error方法即可。
    protected abstract void error(ApiException e);

&#x1f300; 响应转换处理

public class ResponseTransformer implements ObservableTransformer, T> 
    public ResponseTransformer() 
    
    public static  ResponseTransformer obtain()
        return new ResponseTransformer<>();
    
    &#64;NotNull
    &#64;Override
    public ObservableSource apply(&#64;NotNull Observable> upstream) 
        return upstream.onErrorResumeNext(new Function>>() 
            &#64;Override
            public ObservableSource> apply(&#64;NotNull Throwable throwable) throws Exception 
                return Observable.error(ApiException.handleException(throwable));
            
        ).flatMap(new Function, ObservableSource>() 
            &#64;Override
            public ObservableSource apply(&#64;NotNull ResponseData responseData) throws Exception 
                //请求成功&#xff0c;开始处理你的逻辑吧
                if (0&#61;&#61;responseData.getErrorCode()) 
                    if (null!&#61;responseData.getData()) 
                        return Observable.just(responseData.getData());
                     else 
                        //有可能存在返回的数据结果为ull&#xff0c;直接传Null会产生异常。
                        //用过反射创建一个没有内容的数据实例。
                        return Observable.just(responseData.getData());
                    
                
                //请求异常
                return Observable.error(new ApiException(responseData.getErrorCode(), responseData.getErrorMsg()));
            
        ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    

&#x1f300; 封装后使用

数据拿到。


&#x1f525; Hilt(Jetpack成员)

在 Android 上使用Hilt进行依赖注入。Hilt 建立在 Dagger 之上&#xff0c;它提供了一种将 Dagger 依赖注入合并到 Android 应用程序中的标准方法。

官方文档最为致命


&#x1f4a5; 添加依赖(新增)

  implementation &#39;com.google.dagger:hilt-android:2.40.1&#39;
  annotationProcessor &#39;com.google.dagger:hilt-compiler:2.40.1&#39;

&#x1f4a5; Hilt Gradle plugin


&#x1f300; build.gradle(Project)

buildscript 
    repositories 
        google()
        mavenCentral()
    
    dependencies 
        classpath &#39;com.google.dagger:hilt-android-gradle-plugin:2.40.1&#39;
    

&#x1f300; build.gradle(Module)

apply plugin: &#39;dagger.hilt.android.plugin&#39;

&#x1f300; Hilt Application

所有使用 Hilt 的应用程序都必须包含一个用 &#64;HiltAndroidApp 注释的 Application 类。

创建Application

import android.app.Application;
import dagger.hilt.android.HiltAndroidApp;
&#64;HiltAndroidApp
public class App extends Application 

设置AndroidManifest


    package&#61;"com.scc.wanandroid">
    
            android:name&#61;".App"
        ...>
    

准备工作做完了&#xff0c;开始使用Hilt搭建网络框架


&#x1f4a5; 设置OkHttp&#43;Retrofit&#43;RxJava&#43;Hilt


&#x1f300; 创建NetworkModule用来初始化

&#64;InstallIn(SingletonComponent.class)
&#64;Module
public class NetworkModule 
    private static int TIME_OUT &#61; 30; //30秒超时断开连接
    &#64;Provides
    &#64;Singleton
    OkHttpClient providesOkHttpClient()
        HttpLoggingInterceptor loggingInterceptor &#61; new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() 
            &#64;Override
            public void log(String message) 
                try 
                    MLog.e("--network--", URLDecoder.decode(message, "utf-8"));
                 catch (UnsupportedEncodingException e) 
                    e.printStackTrace();
                    MLog.e("--network--", message);
                
            
        );
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        return new OkHttpClient.Builder()
                .sslSocketFactory(new NetworkSSL(TrustManager.trustAllCert), TrustManager.trustAllCert)
                .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
                .addInterceptor(loggingInterceptor)
                .readTimeout(TIME_OUT, TimeUnit.SECONDS)
                .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
                .build();
    
    &#64;Singleton
    &#64;Provides
    Retrofit providesRetrofit(OkHttpClient okHttpClient)
        return new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(IWanAndroidService.BASE_URL)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    
    &#64;Singleton
    &#64;Provides
    IWanAndroidService providesWanAndroidService(Retrofit retrofit)
        return retrofit.create(IWanAndroidService.class);
    

&#x1f300; 使用

&#64;AndroidEntryPoint
public class LoginActivity extends AppCompatActivity 
    ActivityLoginBinding binding;
    &#64;Inject
    IWanAndroidService iWanAndroidService;
    //Retrofit&#43;RxJava&#43;Hilt
        iWanAndroidService.homeBanner()
                .compose(ResponseTransformer.obtain())
                .subscribe(homeBanners -> 
                    //请求成功
                    if (homeBanners !&#61; null) 
                        MLog.e(homeBanners.get(0).toString());
                        binding.loginTvContent.setText(homeBanners.get(0).toString());
                    
                , new ErrorConsumer() 
                    &#64;Override
                    protected void error(ApiException e) 
                        //请求失败
                        MLog.e(e.getMessage()&#43;e.getCode());
                    
                );

&#x1f300; 效果图


&#x1f525; 小结

项目拿到就能用&#xff0c;当然还有可优化的地方。


  • 获取的data为null的时候的处理。

  • 对外隐藏进行网络请求的实现细节。

  • 根据实际情况进一步细化&#xff0c;如API分模块创建等。


&#x1f4a5; 项目传送门


&#x1f525; 链接汇总

&#x1f300; OkHttp Github


&#x1f300; Retrofit Github


&#x1f300; RxJava Github


&#x1f300; Hilt 官方文档最为致命


&#x1f525; 感谢

&#x1f300; 感谢鸿神wanandroid提供的API


&#x1f300; Android Retrofit &#43; RxJava使用详解


&#x1f300; 封装Retrofit2&#43;RxJava2网络请求框架


推荐阅读
author-avatar
拍友2502862603
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有